package archer.application.manager.shiro;

import archer.application.manager.constant.Constant;
import archer.application.manager.service.system.StaffService;

import static archer.framework.protocol.ArcherProtocolModule.*;

import archer.framework.protocol.result.ExecuteResult;
import archer.framework.utils.ValidateUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.web.subject.WebSubject;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

/**
 * @author christ
 * @date 2016/6/12
 */
@Component
public class ShiroRemoteRealm extends AuthorizingRealm implements InitializingBean {

    @Autowired
    StaffService staffService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        ShiroUser user = (ShiroUser) principals.getPrimaryPrincipal();
        if (ValidateUtils.isEmpty(user)) {
            throw new AuthenticationException("用户尚未登录");
        }

        // 用户角色
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        ExecuteResult result = staffService.findMyRoleList();
        if (result.isSuccess() && ValidateUtils.isNotEmpty(result.getResultData())) {
            List<Map> list = (List) result.getResultData();
            for (Map each : list) {
                info.addRole((String) each.get("code"));
            }
        }

        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {

        final HttpServletRequest request = (HttpServletRequest) ((WebSubject) SecurityUtils.getSubject())
                .getServletRequest();
        request.removeAttribute(Constant.LOGIN_ERROR_INFO);

        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;

        String username = token.getUsername();
        String password = String.valueOf(token.getPassword());

        if (ValidateUtils.isEmpty(username) || ValidateUtils.isEmpty(password)) {
            request.setAttribute(Constant.LOGIN_ERROR_INFO, "用户名密码必输");
            throw new AuthenticationException("用户名密码必输");
        }

        // 调用远程接口进行登录认证
        ExecuteResult result = staffService.login(username, password);
        if (result.isSuccess()) {
            Map resultData = (Map) result.getResultData();
            final HttpServletResponse response = (HttpServletResponse) ((WebSubject) SecurityUtils.getSubject())
                    .getServletResponse();

            // cookie token
            response.addCookie(new Cookie(tokenField, (String) resultData.get(tokenField)));

            ShiroUser user = new ShiroUser((String) resultData.get(tokenField), (String) resultData.get("userId"), (String) resultData.get("loginName"));
            return new SimpleAuthenticationInfo(user, null, null, getName());
        }

        request.setAttribute(Constant.LOGIN_ERROR_INFO, result.getResultMsg());

        throw new AuthenticationException("用户名或密码错误");
    }

    public void afterPropertiesSet() throws Exception {

        setCredentialsMatcher(new SimpleCredentialsMatcher());
    }

    public static class ShiroUser {

        public final String token;

        public final String userId;

        public final String loginName;

        public static ShiroUser emptyObject = new ShiroUser(null, null, null);

        public ShiroUser(String token, String userId, String loginName) {
            this.token = token;
            this.userId = userId;
            this.loginName = loginName;
        }
    }
}
